package dexter.net.node;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;

import org.apache.mina.util.AvailablePortFinder;

import dexter.core.host.HostAddress;
import dexter.util.ByteWrapper;

public class AbstractNodeFactory {
	
	public static Collection<AbstractNode> createNodes(Properties props, ClassLoader cl){
		
		int num = Integer.parseInt(props.getProperty("num"));
		
		Collection<AbstractNode> nodes= new Vector<AbstractNode>(num);
		for (int i=0; i<num; i++) {
		  try {
		    AbstractNode node = createNode(props, cl);		    
		    nodes.add(node);
	
		  } catch (Exception e) {
			e.printStackTrace();
		  } 
		}
		return nodes;
	}
	
	public static AbstractNode createNode(Properties props, ClassLoader cl) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, IOException {
		
		String host = props.getProperty("host");
		int port = Integer.parseInt(props.getProperty("port"));
		port = AvailablePortFinder.getNextAvailable(port); //changeBoundPort(host, port);
		System.out.println("Binding : "+host+":"+port);
		HostAddress address = new HostAddress(host, port);				
		
		String session = props.getProperty("session_id");
		String classname = props.getProperty("node_classname");
		
		byte[] classbytes = (byte[]) props.get("node_bytes");	
		
		Class c = null;
		if (classbytes!=null && classbytes.length>0) {
		  String path = props.getProperty("node_filepath");	
		  c = ByteWrapper.loadClassFile(classname, new File(path), cl);
		}
		else c = Class.forName(classname);
			
		
		Constructor ctor = c.getDeclaredConstructor(String.class, HostAddress.class, Hashtable.class);
	    ctor.setAccessible(true);
	    AbstractNode node = (AbstractNode) ctor.newInstance(session, address, (Hashtable) props);
	    
	    return node;
		
	}
	
	
	
}
